package com.tongzhan.service.impl;

import com.alibaba.fastjson.JSON;
import com.tongzhan.base.PageInfo;
import com.tongzhan.base.Return;
import com.tongzhan.data.vo.BillAmountVO;
import com.tongzhan.data.vo.BillDetailsVO;
import com.tongzhan.data.vo.BillTypeVO;
import com.tongzhan.data.vo.BillVO;
import com.tongzhan.entity.User;
import com.tongzhan.entity.religion.*;
import com.tongzhan.repository.UserRepository;
import com.tongzhan.repository.religion.*;
import com.tongzhan.service.BillService;
import com.tongzhan.utils.SnowFlakeUtils;
import com.tongzhan.utils.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class BillServiceImpl implements BillService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private SiteRepository siteRepository;

    @Autowired
    private SiteInfoRepository siteInfoRepository;

    @Autowired
    private BillRepository billRepository;

    @Autowired
    private BillTypeRepository billTypeRepository;

    @Autowired
    private ReligionRepository religionRepository;

    @Autowired
    private ModuleSignRepository signRepository;

    @Override
    public Return newBill(String userId, Bill bill) {
        //用户
        User user = userRepository.findByPrimaryKey(userId);
        if (user == null) {
            return new Return(Return.FAIL, "用户不存在");
        }
        String billCode = bill.getBillCode();
        if (StringUtils.isEmpty(billCode)) {
            //新增
            bill.setDutiesCode(user.getDutiesCode());
            bill.setRealName(user.getRealName());
            if ("03".equals(user.getDutiesCode())) {
                //宗教团体
                Site site = siteRepository.findByPrimaryKey(bill.getSiteCode());
                if (site != null) {
                    bill.setSiteCode(site.getStreetCode());
                    bill.setStreetName(site.getStreetName());
                    bill.setVillageCode(site.getVillageCode());
                    bill.setVillageName(site.getVillageName());
                    bill.setSiteName(site.getSiteName());
                }
            } else if ("04".equals(user.getDutiesCode()) || "07".equals(user.getDutiesCode())) {
                //宗教场所、民间信仰点
                bill.setStreetCode(user.getStreetCode());
                bill.setSiteCode(user.getSiteCode());
                bill.setVillageCode(user.getVillageCode());
                bill.setVillageName(user.getVillageName());
                bill.setSiteName(user.getSiteName());
                bill.setStreetName(user.getStreetName());
            } else {
                return new Return(Return.FAIL, "暂无权限，宗教团体与宗教场所账号才有操作权限");
            }
            bill.setReligionCode(user.getReligionCode());
            bill.setReligionName(user.getReligionName());
            //财务编码
            SnowFlakeUtils snow = new SnowFlakeUtils(4, 3);
            bill.setBillCode(String.valueOf(snow.nextId()));
            bill.setTime(LocalDateTime.now());
            billRepository.insert(bill);
            //新增财务民宗局角标提醒
            List<ModuleSign> signList = signRepository.findAll(new Query().addCriteria(Criteria.where("DutiesCode").is("01")));
            if (!CollectionUtils.isEmpty(signList)) {
                for (ModuleSign sign : signList) {
                    //财务模块角标加一
                    sign.setBill(sign.getBill() + 1);
                    signRepository.updateByPrimaryKey(sign);
                }
            }
            //重置对应用户信息的角标
            Query query = new Query();
            if ("03".equals(user.getDutiesCode())) {
                //宗教团体
                query.addCriteria(Criteria.where("DutiesCode").is("03"));
                query.addCriteria(Criteria.where("ReligionCode").is(user.getReligionCode()));
            }
            if ("04".equals(user.getDutiesCode())) {
                //宗教场所
                query.addCriteria(Criteria.where("DutiesCode").is("04"));
                query.addCriteria(Criteria.where("SiteCode").is(user.getSiteCode()));
            }
            if ("07".equals(user.getDutiesCode())) {
                //民间信仰点
                query.addCriteria(Criteria.where("DutiesCode").is("07"));
                query.addCriteria(Criteria.where("SiteCode").is(user.getSiteCode()));
            }
            List<ModuleSign> moduleSignList = signRepository.findAll(query);
            if (!CollectionUtils.isEmpty(moduleSignList)) {
                for (ModuleSign sign : moduleSignList) {
                    //财务模块角标重置
                    sign.setBill(0L);
                    signRepository.updateByPrimaryKey(sign);
                }
            }
        } else {
            Bill update = billRepository.findByPrimaryKey(billCode);
            if (update != null) {
                bill.setRealName(update.getRealName());
                bill.setDutiesCode(update.getDutiesCode());
                bill.setReligionCode(update.getReligionCode());
                bill.setReligionName(update.getReligionName());
                bill.setTime(update.getTime());
                if ("03".equals(user.getDutiesCode())) {
                    Site site = siteRepository.findByPrimaryKey(bill.getSiteCode());
                    if (site != null) {
                        bill.setSiteCode(site.getSiteCode());
                        bill.setStreetName(site.getStreetName());
                        bill.setVillageCode(site.getVillageCode());
                        bill.setVillageName(site.getVillageName());
                        bill.setSiteName(site.getSiteName());
                    }
                } else {
                    bill.setStreetName(update.getStreetName());
                    bill.setVillageCode(update.getVillageCode());
                    bill.setVillageName(update.getVillageName());
                    bill.setSiteName(update.getSiteName());
                }
            }
            billRepository.updateByPrimaryKey(bill);
        }
        return new Return(Return.SUCCESS, "操作成功");
    }

    @Override
    public Return getBillList(String userId, String year, String religionCode, String siteCode, Integer state, Integer page, Integer size, String month) {
        //用户信息
        User user = userRepository.findByPrimaryKey(userId);
        if (user == null) {
            return new Return(Return.FAIL, "用户不存在");
        }
        //权限编码
        String dutiesCode = user.getDutiesCode();
        //查询条件
        Query query = new Query();
        query.with(Sort.by(Sort.Direction.DESC, "Time"));
        //未上报场所查询条件
        Query search = new Query();
        //封装返回数据
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isEmpty(year)) {
            query.addCriteria(Criteria.where("Year").is(String.valueOf(LocalDate.now().getYear())));
        } else {
            query.addCriteria(Criteria.where("Year").is(year));
        }
        if (StringUtils.isNotEmpty(month) && StringUtils.isEmpty(year)) {
            return new Return(Return.FAIL, "请先选择年份");
        }
        if (StringUtils.isNotEmpty(month)) {
            query.addCriteria(Criteria.where("Month").is(month));
        }
        if ("02".equals(dutiesCode) || ThreadLocalUtil.STREET_CODE.equals(dutiesCode)) {
            //街道权限
            query.addCriteria(Criteria.where("StreetCode").is(user.getStreetCode()));
            search.addCriteria(Criteria.where("StreetCode").is(user.getStreetCode()));
        }
        if ("03".equals(dutiesCode)) {
            //宗教团体权限
            query.addCriteria(Criteria.where("ReligionCode").is(user.getReligionCode()));
            search.addCriteria(Criteria.where("ReligionCode").is(user.getReligionCode()));
        } else {
            if (StringUtils.isNotEmpty(religionCode)) {
                query.addCriteria(Criteria.where("ReligionCode").is(religionCode));
                search.addCriteria(Criteria.where("ReligionCode").is(religionCode));
            }
        }
        if ("05".equals(dutiesCode) || ThreadLocalUtil.VILLAGE_CODE.equals(dutiesCode)) {
            //村社区权限
            query.addCriteria(Criteria.where("VillageCode").is(user.getVillageCode()));
            search.addCriteria(Criteria.where("VillageCode").is(user.getVillageCode()));
        }
        if ("04".equals(dutiesCode) || "07".equals(dutiesCode)) {
            //宗教场所权限、民间信仰点权限
            query.addCriteria(Criteria.where("SiteCode").is(user.getSiteCode()));
            if (state == 0) {
                map.put("unReportedList", new ArrayList<>());
            }
        } else {
            if (StringUtils.isNotEmpty(siteCode)) {
                query.addCriteria(Criteria.where("SiteCode").is(siteCode));
                search.addCriteria(Criteria.where("SiteCode").is(siteCode));
            }
        }
        //重置财务模块角标
        ModuleSign sign = signRepository.findByPrimaryKey(userId);
        if (sign != null) {
            sign.setBill(0L);
            signRepository.updateByPrimaryKey(sign);
        }
        //分页信息
        PageInfo pageInfo = new PageInfo();
        //状态 0-未上报 1-已上报
        if (state == 1) {
            Page<Bill> bills = billRepository.findPage(query, PageRequest.of(page - 1, size));
            pageInfo.setPage(page);
            pageInfo.setSize(bills.getContent().size());
            pageInfo.setTotal(bills.getTotalElements());
            //VO
            List<BillVO> vos = new ArrayList<>();
            if (!CollectionUtils.isEmpty(bills.getContent())) {
                for (Bill bill : bills.getContent()) {
                    BillVO vo = new BillVO();
                    vo.setBillCode(bill.getBillCode());
                    vo.setRealName(bill.getRealName());
                    vo.setSiteName(bill.getSiteName());
                    vo.setTime(bill.getTime());
                    vos.add(vo);
                }
            }
            map.put("billList", vos);
        } else if (state == 0 && ("00".equals(dutiesCode) || "01".equals(dutiesCode)
                || "02".equals(dutiesCode)) || "03".equals(dutiesCode) || "05".equals(dutiesCode)) {
            //记录已上报的场所列表
            List<String> list = new ArrayList<>();
            List<Bill> billList = billRepository.findAll(query);
            for (Bill bill : billList) {
                if (!list.contains(bill.getSiteCode())) {
                    list.add(bill.getSiteCode());
                }
            }
            if (StringUtils.isEmpty(siteCode)) {
                search.addCriteria(Criteria.where("SiteCode").nin(list));
            }
            //查询未上报
            Page<Site> sitePage = siteRepository.findPage(search, PageRequest.of(page - 1, size));
            List<Map<String, Object>> unReportedList = new ArrayList<>();
            //判断该场所本月是否上报
            if (list.contains(siteCode)) {
                pageInfo.setPage(page);
                pageInfo.setSize(0);
                pageInfo.setTotal(0L);
            } else {
                for (Site site : sitePage.getContent()) {
                    Map<String, Object> siteMap = new HashMap<>();
                    siteMap.put("siteName", site.getSiteName());
                    SiteInfo siteInfo = siteInfoRepository.findOne(new Query().addCriteria(Criteria.where("SiteCode").is(site.getSiteCode())));
                    if (siteInfo != null) {
                        siteMap.put("siteTelephone", siteInfo.getPersonTelephone());
                    } else {
                        siteMap.put("siteTelephone", null);
                    }
                    unReportedList.add(siteMap);
                }
                pageInfo.setPage(page);
                pageInfo.setSize(sitePage.getContent().size());
                pageInfo.setTotal(sitePage.getTotalElements());
            }
            map.put("unReportedList", unReportedList);
        }
        map.put("pageInfo", pageInfo);
        return new Return(map);
    }

    @Override
    public Return getAmount(String userId) {
        User user = userRepository.findByPrimaryKey(userId);
        if (user == null) {
            return new Return(Return.FAIL, "用户不存在");
        }
        //场所上报的财务列表
        List<Bill> billList
                = billRepository.findAll(new Query().addCriteria(Criteria.where("SiteCode").is(user.getSiteCode())));
        //VO
        BillAmountVO vo = new BillAmountVO();
        vo.setSiteName(user.getSiteName());
        vo.setStreetName(user.getStreetName());
        vo.setReligionCode(user.getReligionCode());
        vo.setReligionName(user.getReligionName());
        vo.setYear(String.valueOf(LocalDate.now().getYear()));
        //上月累计收入金额
        BigDecimal preMonthTotalInput = BigDecimal.ZERO;
        //本月累计收入金额
        BigDecimal curMonthTotalInput = BigDecimal.ZERO;
        //上月累计支出金额
        BigDecimal preMonthTotalOutput = BigDecimal.ZERO;
        //本月累计支出金额
        BigDecimal curMonthTotalOutput = BigDecimal.ZERO;
        if (!CollectionUtils.isEmpty(billList)) {
            for (Bill bill : billList) {
                //财务上报时间
                LocalDate reportTime = bill.getTime().toLocalDate();
                //现在月份
                int nowMonth = LocalDate.now().getMonthValue();
                //上个月月份
                int preMonth = LocalDate.now().minusMonths(1).getMonthValue();
                if (reportTime.getMonthValue() == nowMonth) {
                    //本月
                    curMonthTotalInput = curMonthTotalInput.add(bill.getMonthTotalRevenue());
                    curMonthTotalOutput = curMonthTotalOutput.add(bill.getMonthTotalOutPut());
                } else if (reportTime.getMonthValue() == preMonth) {
                    //上月
                    preMonthTotalInput = preMonthTotalInput.add(bill.getMonthTotalRevenue());
                    preMonthTotalOutput = preMonthTotalOutput.add(bill.getMonthTotalOutPut());
                }
            }
        }
        vo.setPreMonthAmount(preMonthTotalInput.subtract(preMonthTotalOutput));
        vo.setCurMonthAmount(curMonthTotalInput.subtract(curMonthTotalOutput));
        return new Return(vo);
    }

    @Override
    public Return billDetails(String billCode) {
        Bill bill = billRepository.findByPrimaryKey(billCode);
        BillDetailsVO vo = new BillDetailsVO();
        //封装数据
        vo.setDescribe(bill.getContent());
        BeanUtils.copyProperties(bill, vo);
        //财务收入类
        Map<String,Object> revenueMap = (Map<String, Object>) this.getBillTypeList(0, bill.getReligionCode()).getData();
        List<BillTypeVO> revenueAllList = (List<BillTypeVO>) revenueMap.get("billTypeList");
        List<BillTypeVO> revenueList = JSON.parseArray(bill.getRevenueData(), BillTypeVO.class);
        Map<String, BillTypeVO> revenueListMap = revenueList.stream().collect(Collectors.toMap(BillTypeVO::getBillTypeCode, Function.identity()));

        for (BillTypeVO typeVO : revenueAllList) {
//            BillType billType = billTypeRepository.findByPrimaryKey(typeVO.getBillTypeCode());
            BillTypeVO billType = revenueListMap.get(typeVO.getBillTypeCode());
            if (billType != null) {
                typeVO.setMonthAmount(billType.getMonthAmount());
            }else {
                typeVO.setMonthAmount(BigDecimal.ZERO);
            }
        }
        //财务支出类
        Map<String,Object> outPutMap = (Map<String, Object>) this.getBillTypeList(1, bill.getReligionCode()).getData();
        List<BillTypeVO> outPutAllList = (List<BillTypeVO>) outPutMap.get("billTypeList");
        List<BillTypeVO> outPutList = JSON.parseArray(bill.getOutPutData(), BillTypeVO.class);
        Map<String, BillTypeVO> outPutListMap = outPutList.stream().collect(Collectors.toMap(BillTypeVO::getBillTypeCode, Function.identity()));
        for (BillTypeVO typeVO : outPutAllList) {
//            BillType billType = billTypeRepository.findByPrimaryKey(typeVO.getBillTypeCode());
            BillTypeVO billType = outPutListMap.get(typeVO.getBillTypeCode());
            if (billType != null) {
                typeVO.setMonthAmount(billType.getMonthAmount());
            }else {
                typeVO.setMonthAmount(BigDecimal.ZERO);
            }
        }
        vo.setRevenueList(revenueAllList);
        vo.setOutPutList(outPutAllList);
        return new Return(vo);
    }

    @Override
    public Return getBillTypeList(Integer type, String religionCode) {
        if ("04".equals(religionCode)) {
            //民间信仰点的收入类和支出类按照佛教的标准
            religionCode = "01";
        }
        //财务类型列表
        List<BillType> typeList = billTypeRepository.findAll(new Query().addCriteria(Criteria.where("Type").is(type))
                .addCriteria(Criteria.where("ReligionCode").is(religionCode)));
        //VO
        List<BillTypeVO> vos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(typeList)) {
            for (BillType billType : typeList) {
                BillTypeVO vo = new BillTypeVO();
                vo.setBillTypeCode(billType.getBillTypeCode());
                vo.setBillTypeName(billType.getBillTypeName());
                vos.add(vo);
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("billTypeList", vos);
        return new Return(map);
    }

    @Override
    public Return editBillType(String billTypeCode, String billTypeName, Integer type, String religionCode) {
        //宗教
        Religion religion = religionRepository.findByPrimaryKey(religionCode);
        if (religion == null) {
            return new Return(Return.FAIL, "宗教不存在");
        }
        if (StringUtils.isEmpty(billTypeCode)) {
            //新增
            SnowFlakeUtils snow = new SnowFlakeUtils(4, 9);
            BillType billType = new BillType();
            billType.setBillTypeCode(String.valueOf(snow.nextId()));
            billType.setBillTypeName(billTypeName);
            billType.setType(type);
            billType.setReligionCode(religion.getReligionCode());
            billType.setReligionName(religion.getReligionName());
            billType.setCreateTime(LocalDateTime.now());
            billTypeRepository.insert(billType);
        } else {
            //修改
            BillType billType = billTypeRepository.findByPrimaryKey(billTypeCode);
            if (billType == null) {
                return new Return(Return.FAIL, "财务类型不存在");
            }
            billType.setBillTypeName(billTypeName);
            billType.setType(type);
            billType.setReligionCode(religion.getReligionCode());
            billType.setReligionName(religion.getReligionName());
            billType.setUpdateTime(LocalDateTime.now());
            billTypeRepository.updateByPrimaryKey(billType);
        }
        return new Return(Return.SUCCESS, "操作成功");
    }

    @Override
    public Return deleteBillType(String billTypeCode) {
        billTypeRepository.delete(new Query().addCriteria(Criteria.where("BillTypeCode").is(billTypeCode)));
        return new Return(Return.SUCCESS, "操作成功");
    }

    @Override
    public List<String> selectReport(String year, String month, String dutiesCode) {
        //查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("Year").is(year).and("Month").is(month)
                .and("DutiesCode").is(dutiesCode));
        List<Bill> billList = billRepository.findAll(query);
        List<String> codes = new ArrayList<>();
        if (!CollectionUtils.isEmpty(billList)) {
            for (Bill bill : billList) {
                //宗教团体
                if ("03".equals(dutiesCode) && !codes.contains(bill.getReligionCode())) {
                    codes.add(bill.getReligionCode());
                }
                //宗教场所
                if ("04".equals(dutiesCode) && !codes.contains(bill.getSiteCode())) {
                    codes.add(bill.getSiteCode());
                }
                //民间信仰点
                if ("07".equals(dutiesCode) && !codes.contains(bill.getSiteCode())) {
                    codes.add(bill.getSiteCode());
                }
            }
        }
        return codes;
    }

    @Override
    public void delete(String billCode) {
        billRepository.deletePrimaryKey(billCode);
    }
}
